
Imports System.IO

Public Module base
    Public Function ifoper(Of t)(ByVal v As Boolean, ByVal a As t, ByVal b As t) As t
        If v Then
            Return a
        Else
            Return b
        End If
    End Function

    Public Function min(ByVal first As Int32, ByVal second As Int32) As Int32
        Return ifoper(first < second, first, second)
    End Function

    Public Function min(ByVal first As UInt32, ByVal second As UInt32) As UInt32
        Return ifoper(first < second, first, second)
    End Function

    Public Function min(ByVal first As Int64, ByVal second As Int64) As Int64
        Return ifoper(first < second, first, second)
    End Function

    Public Function min(ByVal first As UInt64, ByVal second As UInt64) As UInt64
        Return ifoper(first < second, first, second)
    End Function

    Public Function min(Of valueT)(ByVal first As valueT, ByVal second As valueT) As valueT
        If compare(first, second) < 0 Then
            Return first
        Else
            Return second
        End If
    End Function

    Public Function max(ByVal first As Int32, ByVal second As Int32) As Int32
        Return ifoper(first < second, second, first)
    End Function

    Public Function max(ByVal first As UInt32, ByVal second As UInt32) As UInt32
        Return ifoper(first < second, second, first)
    End Function

    Public Function max(ByVal first As Int64, ByVal second As Int64) As Int64
        Return ifoper(first < second, second, first)
    End Function

    Public Function max(ByVal first As UInt64, ByVal second As UInt64) As UInt64
        Return ifoper(first < second, second, first)
    End Function

    Public Function max(Of valueT)(ByVal first As valueT, ByVal second As valueT) As valueT
        If compare(first, second) > 0 Then
            Return first
        Else
            Return second
        End If
    End Function

    Public Sub sleep(Optional ByVal ms As Int32 = 1000)
        If ms >= 0 Then
            System.Threading.Thread.Sleep(ms)
        End If
    End Sub

    Public Sub sleepSeconds(Optional ByVal s As Int32 = 1)
        Dim i As Int64 = 0
        i = secondsToMilliseconds(s)
        If i > maxInt32 Then
            sleep(maxInt32)
        ElseIf i < minInt32 Then
            sleep(minInt32)
        Else
            sleep(i)
        End If
    End Sub

    Public Sub sleepTicks(Optional ByVal t As Int64 = 10000000)
        If t >= 0 Then
            System.Threading.Thread.Sleep(TimeSpan.FromTicks(t))
        End If
    End Sub

    Public Function alloc(ByVal t As Type) As Object
        Dim obj As Object = Nothing
        If t Is Nothing Then
            obj = Nothing
        Else
            If t.IsArray() OrElse t.IsValueType() Then
                obj = Nothing
            Else
                Try
                    eva(obj, Activator.CreateInstance(t, True))
                Catch ex As Exception
                    If isdebugmode() Then
                        raiseError(errorHandle.errorType.warning,
                                   "failed to create instance of type ", t.AssemblyQualifiedName(),
                                   " by Activator, ex ", ex.Message)
                    End If
                End Try
                If obj Is Nothing Then
                    Dim constructors As Reflection.ConstructorInfo() = Nothing
                    Try
                        constructors =
                            t.GetConstructors(Reflection.BindingFlags.Public Or Reflection.BindingFlags.NonPublic)
                    Catch ex As Exception
                        If isdebugmode() Then
                            raiseError(errorHandle.errorType.warning,
                                       "failed to get constructors of type ", t.AssemblyQualifiedName(),
                                       ", ex ", ex.Message)
                        End If
                    End Try
                    'save a compare here
                    If constructors Is Nothing OrElse constructors.Length = 0 Then
                        obj = Nothing
                    Else
                        Dim parameters(constructors(0).GetParameters().Length - 1) As Object
                        'assert vb.net will clear the array here
                        'memclr(parameters, 0, parameters.Length())
                        Try
                            obj = constructors(0).Invoke(parameters)
                        Catch ex As Exception
                            If isdebugmode() Then
                                raiseError(errorHandle.errorType.warning,
                                           "failed to invoke constructors of type ", t.AssemblyQualifiedName(),
                                           ", ex ", ex.Message)
                            End If
                        End Try
                        'assert(Not obj Is Nothing, "allocate of type " + t.FullName + " failed")
                    End If
                End If
            End If
        End If
        Return obj
    End Function

    Public Function alloc(Of valueT)() As valueT
        Try
            'valueT As New
            Return Activator.CreateInstance(Of valueT)()
        Catch
            'there is not a constructor without parameters
            Return alloc(GetType(valueT))
        End Try
    End Function

    Public Function alloc(Of T)(ByVal obj As T) As T
        If obj Is Nothing Then
            Return alloc(Of T)()
        Else
            Return alloc(obj.GetType())
        End If
    End Function

    Public Sub swap(Of valueT)(ByRef this As valueT, ByRef that As valueT)
        Dim temp As valueT = Nothing
        temp = this
        this = that
        that = temp
    End Sub

    Public Function containNothing(ByVal ins As Object(), ByVal start As Int32, ByVal [end] As Int32) As Boolean
        Dim i As Int32
        For i = start To [end] - 1
            If ins(i) Is Nothing Then
                Exit For
            End If
        Next

        Return i < [end]
    End Function

    Public Function containEndOfStream(ByVal readers As StreamReader() _
                                        , ByVal start As Int32, ByVal [end] As Int32) As Boolean
        Dim i As Int32
        For i = start To [end] - 1
            If readers(i).EndOfStream Then
                Exit For
            End If
        Next

        Return i < [end]
    End Function

    Public Function createGUID() As String
        Return Guid.NewGuid().ToString()
    End Function

    Public Function createGUID(ByVal count As Int64, Optional ByVal separator As String = character.newline) As String
        Dim rtn As String = Nothing
        While count > 1
            rtn += createGUID() + separator
            count -= 1
        End While
        If count > 0 Then
            rtn += createGUID()
        End If

        Return rtn
    End Function

    Public Function inputline(ByVal s As String) As String
        Console.Write(s)
        Return Console.ReadLine
    End Function

    Public Function memorySizeDisplay(ByVal input As UInt64 _
                                    , Optional ByVal displayOriginalSize As Boolean = True _
                                    , Optional ByVal originalSizeSeperator As String _
                                    = character.leftBrace + character.rightBrace) As String
        Dim in2 As Double = input
        Static Dim unit() As String = {"B", "KB", "MB", "GB", "TB"}
        Dim i As Int32
        i = 0
        While in2 > 1024 AndAlso i < unit.Length() - 1
            in2 /= 1024
            i += 1
        End While

        Dim rtn As String = Convert.ToString(in2)
        Dim index As Int32 = rtn.IndexOf(character.dot)
        If index <> npos Then
            rtn = strleft(rtn, index + 3)
        End If
        rtn += unit(i)
        If displayOriginalSize AndAlso i > 0 Then
            If strlen(originalSizeSeperator) >= 2 Then
                rtn += character.blank + originalSizeSeperator(0) + _
                       Convert.ToString(input) + unit(0) + _
                       originalSizeSeperator(1)
            ElseIf strlen(originalSizeSeperator) = 1 Then
                rtn += character.blank + originalSizeSeperator(0) + _
                       Convert.ToString(input) + unit(0) + _
                       originalSizeSeperator(0)
            Else
                rtn += character.blank + Convert.ToString(input) + unit(0)
            End If
        End If
        Return rtn
    End Function

    Public Function sizeof(Of t)() As Int32
        Return sizeof(GetType(t))
    End Function

    Public Function sizeof(Of t)(ByVal obj As t) As Int32
        Try
            Return System.Runtime.InteropServices.Marshal.SizeOf(obj)
        Catch
            Return npos
        End Try
    End Function

    Public Function sizeof(ByVal t As Type) As Int32
        Try
            Return System.Runtime.InteropServices.Marshal.SizeOf(t)
        Catch
            Return npos
        End Try
    End Function

    Public Sub memcpy(Of T)(ByVal dest() As T, ByVal deststart As Int32, _
                            ByVal src() As T, ByVal srcstart As Int32, ByVal count As Int32)
        memmove(dest, deststart, src, srcstart, count)
    End Sub

    Public Sub memcpy(Of T)(ByVal dest() As T, ByVal src() As T)
        assert(Not src Is Nothing)
        memcpy(dest, 0, src, 0, src.Length())
    End Sub

    Public Sub memcpy(Of T)(ByVal dest() As T, ByVal deststart As Int32, ByVal src() As T)
        assert(Not src Is Nothing)
        memcpy(dest, deststart, src, 0, src.Length())
    End Sub

    Public Sub memmove(Of T)(ByVal dest() As T, ByVal deststart As Int32, _
                             ByVal src() As T, ByVal srcstart As Int32, ByVal count As Int32)
        If count > 0 Then
            Array.Copy(src, srcstart, dest, deststart, count)
        End If
    End Sub

    Public Sub memset(Of T)(ByVal dest() As T, ByVal start As Int32, ByVal count As Int32, ByVal src As T)
        Dim i As Int32
        For i = start To start + count - 1
            copy(dest(i), src)
        Next
    End Sub

    Public Sub memset(Of T)(ByVal dest() As T, ByVal src As T)
        memset(dest, 0, dest.Length(), src)
    End Sub

    Public Sub memclr(Of T)(ByVal dest() As T, ByVal start As Int32, ByVal count As Int32)
        For i As Int32 = start To start + count - 1
            dest(i) = Nothing
        Next
    End Sub

    Public Sub memclr(Of T)(ByVal dest() As T)
        memclr(dest, 0, dest.Length)
    End Sub

    Public Function memcmp(Of T)(ByVal first() As T, ByVal firstStart As Int64, _
                                 ByVal second() As T, ByVal secondStart As Int64, ByVal len As Int64) As Int32
        If len = 0 Then
            Return 0
        Else
            assert(Not first Is Nothing AndAlso first.Length() >= firstStart + len _
                   , "first is not long enough to firstStart + len.")
            assert(Not second Is Nothing AndAlso second.Length() >= secondStart + len _
                   , "second is not long enough to secondStart + len.")

            Dim i As Int64
            For i = 0 To len - 1
                Dim cmp As Int64
                cmp = compare(first(i + firstStart), second(i + secondStart))
                If cmp <> 0 Then
                    Return cmp
                End If
            Next

            Return 0
        End If
    End Function

    Public Function memcmp(Of T)(ByVal first() As T, ByVal second() As T, ByVal len As Int64) As Int32
        Return memcmp(first, 0, second, 0, len)
    End Function

    Public Function memcmp(Of T)(ByVal first() As T, ByVal second() As T) As Int32
        If first Is Nothing AndAlso second Is Nothing Then
            Return 0
        ElseIf first Is Nothing Then
            Return -second.Length()
        ElseIf second Is Nothing Then
            Return first.Length()
        ElseIf first.Length() <> second.Length() Then
            Return first.Length() - second.Length()
        Else
            Return memcmp(first, 0, second, 0, first.Length())
        End If
    End Function

    Public Function gcd(ByVal a As Int64, ByVal b As Int64) As Int64
        If a = 0 Then
            Return b
        End If
        If b = 0 Then
            Return a
        End If
        If a < b Then
            swap(a, b)
        End If
        Dim c As Int64
        c = a Mod b
        While c > 0
            a = b
            b = c
            c = a Mod b
        End While

        Return b
    End Function

    Public ReadOnly buildInfo2 As String = strcat(applicationSign(), " is built @ ",
                                                  buildtime, " on ", buildmachine, " by ", builduser,
                                                  ", cpu-arch ", buildprocessor)

    Public Sub selfincrease(Of t)(ByRef i As t, ByVal j As t)
        i = convertor.cast(Of t)(convertor.cast(Of Object)(i) + convertor.cast(Of Object)(j))
    End Sub

    Public Sub shift(ByRef b As UInt32, ByVal moves As Byte)
        assert(moves < sizeof(b) * 8, "cannot shift a variable over its size*8.")
        If moves > 0 Then
            b = (b >> moves) + ((b And (pow2(moves) - 1)) << (32 - moves))
        End If
    End Sub

    Public Function sort(Of T)(ByVal ds() As T, Optional ByVal start As Int32 = 0, _
                               Optional ByVal [end] As Int32 = npos) As Boolean
        If ds Is Nothing Then
            Return False
        ElseIf ds.Length() = 0 Then
            Return True
        End If

        If [end] = npos Then
            [end] = ds.Length()
        End If

        Try
            Array.Sort(ds, start, [end] - start)
            Return True
        Catch 'ex As Exception  'do not log here
            Return False
        End Try
    End Function

    Public Sub languageSeparate(ByVal full As String, ByRef market As String, ByRef language As String)
        If isemptystring(full) Then
            market = Nothing
            language = Nothing
        Else
            Dim index As Int64
            index = strindexof(full, network.languageSeparator, False)
            If index <> npos Then
                market = strleft(full, index)
            Else
                copy(market, full)
            End If

            index = strindexof(market, network.languageCountrySeparator, False)
            If index <> npos Then
                language = strleft(market, index)
            Else
                language = Nothing
            End If
        End If
    End Sub

    Public Function _false(ByVal ParamArray a() As Object) As Boolean
        Return False
    End Function

    Public Function _true(ByVal ParamArray a() As Object) As Boolean
        Return True
    End Function

    Public Function _inc(ByRef i As Int64, ByVal j As Int64) As Int64
        i += j
        Return i
    End Function

    Public Function _inc(ByRef i As Int64) As Int64
        Return _inc(i, 1)
    End Function

    Public Function _inc(ByRef i As Int32, ByVal j As Int32) As Int32
        i += j
        Return i
    End Function

    Public Function _inc(ByRef i As Int32) As Int32
        Return _inc(i, 1)
    End Function

    Public Function _inc(ByRef i As Object) As Object
        i += 1
        Return i
    End Function

    Public Function inc_(ByRef i As Int64, ByVal j As Int64) As Int64
        Dim o As Int64 = 0
        o = i
        i += j
        Return o
    End Function

    Public Function inc_(ByRef i As Int64) As Int64
        Return inc_(i, 1)
    End Function

    Public Function inc_(ByRef i As Int32, ByVal j As Int32) As Int32
        Dim o As Int32 = 0
        o = i
        i += j
        Return o
    End Function

    Public Function inc_(ByRef i As Int32) As Int32
        Return inc_(i, 1)
    End Function

    Public Function inc_(ByRef i As Object) As Object
        Dim j As Object = Nothing
        copy(j, i)
        i += 1
        Return j
    End Function

    Public Function inc(ByRef i As Object) As Object
        Return _inc(i)
    End Function

    Public Function _dec(ByRef i As Object) As Object
        i -= 1
        Return i
    End Function

    Public Function dec_(ByRef i As Object) As Object
        Dim j As Object = Nothing
        copy(j, i)
        i -= 1
        Return j
    End Function

    Public Function dec(ByRef i As Object) As Object
        Return _dec(i)
    End Function

    Public Function inc(ByRef a As Object, ByVal b As Object) As Boolean
        a += b
        Return True
    End Function

    Public Function dec(ByRef a As Object, ByVal b As Object) As Boolean
        a -= b
        Return True
    End Function

    Public Function eva(Of T)(ByRef a As T, ByVal b As T) As Boolean
        a = b
        Return True
    End Function

    Public Function eva(Of T)(ByRef a As T, ByVal b As _do(Of T)) As Boolean
        If b Is Nothing Then
            Return False
        Else
            a = b()
            Return True
        End If
    End Function

    Public Function eva(Of T)(ByVal p As pointer(Of T), ByVal v As T) As Boolean
        Return eva(p,
                   Function() As T
                       Return v
                   End Function)
    End Function

    Public Function eva(Of T)(ByVal p As pointer(Of T), ByVal v As _do(Of T)) As Boolean
        If v Is Nothing Then
            Return False
        Else
            If Not p Is Nothing Then
                p.set(v())
            End If
            Return True
        End If
    End Function

    Public Function eva_return(Of T)(ByRef a As T, ByVal b As T) As T
        a = b
        Return a
    End Function

    Public Function unref(Of T)(ByRef a As T) As T
        Return a
    End Function

    Public Function isemptyarray(Of T)(ByVal a() As T) As Boolean
        Return a Is Nothing OrElse a.Length() = 0
    End Function

    Public Function between(Of T)(ByVal i As T, ByVal l As T, ByVal u As T) As Boolean
        Return compare(i, l) > 0 AndAlso compare(i, u) < 0
    End Function

    Public Sub [erase](Of T)(ByRef a() As T)
        If Not a Is Nothing Then
            Erase a
            ReDim a(-1)
            a = Nothing
        End If
    End Sub

    Public Function paramarray_get(Of T)(ByVal index As Int64, ByRef rtn As T, ByVal needAssert As Boolean, _
                                         ByVal ParamArray ps() As Object) As Boolean
        If ps Is Nothing OrElse ps.Length() <= index Then
            If needAssert Then
                assert(False)
            End If
            Return False
        End If

        If convertor.cast(Of T)(ps(index), rtn) Then
            Return True
        Else
            If needAssert Then
                assert(False)
            End If
            Return False
        End If
    End Function

    Public Function paramarray_get(Of T)(ByVal index As Int64, ByRef rtn As T, _
                                         ByVal ParamArray ps() As Object) As Boolean
        Return paramarray_get(index, rtn, True, ps)
    End Function

    Public Function paramarray_get(Of T)(ByVal index As Int64, ByVal needAssert As Boolean, _
                                         ByVal ParamArray ps() As Object) As T
        Dim rtn As T = Nothing
        If paramarray_get(index, rtn, needAssert, ps) Then
            Return rtn
        Else
            Return Nothing
        End If
    End Function

    Public Function paramarray_get(Of T)(ByVal index As Int64, ByVal ParamArray ps() As Object) As T
        Return paramarray_get(Of T)(index, True, ps)
    End Function

    Public Sub fake_work(Optional ByVal ticks As Int64 = 10000)
        Dim i As Int64
        While i < ticks
            i += rnd(-1, 10, True)
        End While
    End Sub

    Public Function synced(ByVal i As IAsyncResult) As Boolean
        assert(Not i Is Nothing)
        assert(Not i.CompletedSynchronously() OrElse i.IsCompleted())
        Return i.CompletedSynchronously()
    End Function

    Public Function asynced(ByVal i As IAsyncResult) As Boolean
        Return Not synced(i)
    End Function

    Public Function [default](Of T)() As T
        Return Nothing
    End Function

    'TODO: move to a project without integer overflow check
    Public Function safe_increase(ByRef i As Int32, Optional ByVal j As Int32 = 1) As Boolean
        Try
            i += j
        Catch
            Return False
        End Try

        Return True
    End Function

    Public Function safe_increase(ByRef i As Int64, Optional ByVal j As Int64 = 1) As Boolean
        Try
            i += j
        Catch
            Return False
        End Try

        Return True
    End Function

    Public Function enum_traversal(Of T)(ByVal d As void(Of T, String),
                                         Optional ByVal count As void(Of Int64) = Nothing) As Boolean
        If d Is Nothing Then
            Return False
        Else
            Dim ct As Type = Nothing
            ct = GetType(T)
            If ct.IsEnum() Then
                Dim values As Array = Nothing
                values = [Enum].GetValues(ct)
                void_(count, values.Length())
                For Each value As T In values
                    d(value, [Enum].GetName(ct, value))
                Next

                Return True
            Else
                Return False
            End If
        End If
    End Function
End Module
